package com.example.pdfprocessor.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class WordService {

    @Value("${app.upload.dir}")
    private String uploadDir;

    private File uploadDirFile;

    @PostConstruct
    public void init() {
        try {
            log.info("初始化Word处理服务，配置的上传目录: {}", uploadDir);
            
            // 创建绝对路径
            uploadDirFile = new File(uploadDir);
            
            // 创建多级目录
            if (!uploadDirFile.exists()) {
                boolean created = uploadDirFile.mkdirs();
                if (!created) {
                    log.error("无法创建上传目录: {}", uploadDirFile.getAbsolutePath());
                    throw new RuntimeException("无法创建上传目录: " + uploadDirFile.getAbsolutePath());
                }
            }
            
            log.info("上传目录创建成功: {}", uploadDirFile.getAbsolutePath());
            
            // 验证目录是否可写
            if (!uploadDirFile.canWrite()) {
                log.error("上传目录没有写入权限: {}", uploadDirFile.getAbsolutePath());
                throw new RuntimeException("上传目录没有写入权限: " + uploadDirFile.getAbsolutePath());
            }
        } catch (Exception e) {
            log.error("初始化Word处理服务失败", e);
            throw new RuntimeException("无法初始化Word处理服务", e);
        }
    }

    /**
     * 处理Word文档，移除页眉页脚但保留页码
     * @param file 上传的Word文档
     * @return 处理后的文件名
     */
    public String processWordDocument(MultipartFile file) throws IOException {
        String originalFilename = file.getOriginalFilename();
        log.info("处理Word文档: {}", originalFilename);
        
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }
        
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String uniqueFilename = UUID.randomUUID().toString() + fileExtension;
        File outputFile = new File(uploadDirFile, uniqueFilename);
        
        log.info("输出文件路径: {}", outputFile.getAbsolutePath());
        
        // 确保上传目录存在
        if (!uploadDirFile.exists()) {
            boolean created = uploadDirFile.mkdirs();
            if (!created) {
                throw new IOException("无法创建目录: " + uploadDirFile.getAbsolutePath());
            }
        }
        
        // 直接从MultipartFile流处理，不保存中间文件
        try (InputStream inputStream = file.getInputStream();
             XWPFDocument document = new XWPFDocument(inputStream);
             FileOutputStream out = new FileOutputStream(outputFile)) {
            
            // 处理页眉
            removeHeaders(document);
            
            // 处理页脚，但保留页码
            removeFootersKeepPageNumbers(document);
            
            // 保存处理后的文档
            document.write(out);
            log.info("Word文档处理完成并保存至: {}", outputFile.getAbsolutePath());
        } catch (Exception e) {
            log.error("处理Word文档失败", e);
            throw new IOException("处理Word文档失败: " + e.getMessage(), e);
        }
        
        return uniqueFilename;
    }
    
    /**
     * 移除Word文档中的所有页眉
     * @param document Word文档对象
     */
    private void removeHeaders(XWPFDocument document) {
        // 获取所有页眉
        List<XWPFHeader> headers = document.getHeaderList();
        if (headers != null && !headers.isEmpty()) {
            // 遍历所有页眉
            for (XWPFHeader header : headers) {
                // 清空页眉内容
                for (XWPFParagraph p : header.getParagraphs()) {
                    for (int i = p.getRuns().size() - 1; i >= 0; i--) {
                        p.removeRun(i);
                    }
                }
                
                // 移除表格 - 保存表格列表的副本，然后逐个移除
                List<XWPFTable> tables = new ArrayList<>(header.getTables());
                for (XWPFTable table : tables) {
                    header.removeTable(table);
                }
            }
        }
        
        // 确保所有节都没有页眉
        for (XWPFParagraph p : document.getParagraphs()) {
            CTSectPr sectPr = p.getCTP().getPPr() != null ? p.getCTP().getPPr().getSectPr() : null;
            if (sectPr != null) {
                // 移除所有页眉引用
                CTHdrFtrRef[] headerRefs = sectPr.getHeaderReferenceArray();
                if (headerRefs != null && headerRefs.length > 0) {
                    for (int i = 0; i < headerRefs.length; i++) {
                        sectPr.removeHeaderReference(i);
                    }
                }
            }
        }
        
        // 处理文档级别的节
        CTSectPr sectPr = document.getDocument().getBody().getSectPr();
        if (sectPr != null) {
            CTHdrFtrRef[] headerRefs = sectPr.getHeaderReferenceArray();
            if (headerRefs != null && headerRefs.length > 0) {
                for (int i = 0; i < headerRefs.length; i++) {
                    sectPr.removeHeaderReference(i);
                }
            }
        }
    }
    
    /**
     * 移除Word文档中的页脚，但保留页码
     * @param document Word文档对象
     */
    private void removeFootersKeepPageNumbers(XWPFDocument document) {
        log.info("开始处理页脚，保留页码...");
        try {
            // 获取所有页脚
            List<XWPFFooter> footers = document.getFooterList();
            if (footers != null && !footers.isEmpty()) {
                log.info("文档包含{}个页脚", footers.size());
                // 遍历所有页脚
                for (XWPFFooter footer : footers) {
                    // 处理页脚中的段落
                    List<XWPFParagraph> paragraphs = new ArrayList<>(footer.getParagraphs());
                    for (XWPFParagraph p : paragraphs) {
                        processFooterParagraph(p);
                    }
                    
                    // 移除页脚中的表格，但保留包含页码的表格
                    List<XWPFTable> tables = new ArrayList<>(footer.getTables());
                    for (XWPFTable table : tables) {
                        processFooterTable(footer, table);
                    }
                    
                    // 清除不可见的内容和其他页脚元素
                    try {
                        cleanUpFooterElements(footer);
                    } catch (Exception e) {
                        log.error("清理页脚元素时出错: {}", e.getMessage());
                    }
                }
            } else {
                log.info("文档没有页脚");
            }
            
            // 处理文档级别的页脚设置
            try {
                cleanupDocumentFooterSettings(document);
            } catch (Exception e) {
                log.error("清理文档页脚设置时出错: {}", e.getMessage());
            }
        } catch (Exception e) {
            log.error("处理页脚时发生异常: {}", e.getMessage(), e);
        }
        log.info("页脚处理完成");
    }
    
    /**
     * 处理页脚段落，保留包含页码的部分
     */
    private void processFooterParagraph(XWPFParagraph p) {
        try {
            boolean hasPageNumber = false;
            String paragraphText = p.getText();
            
            log.debug("处理页脚段落: '{}'", paragraphText);
            
            // 检查段落是否包含页码
            if (paragraphText != null && containsPageNumber(paragraphText)) {
                log.info("通过文本内容检测到页码: '{}'", paragraphText);
                hasPageNumber = true;
            }
            
            // 检查段落XML是否包含页码指示器
            if (!hasPageNumber) {
                String xmlString = p.getCTP().xmlText();
                if (xmlString != null && (
                    xmlString.contains("w:fldChar") || 
                    xmlString.contains("PAGE") || 
                    xmlString.contains("NUMPAGES") || 
                    xmlString.contains("w:instrText"))) {
                    log.info("通过XML标记检测到页码标记");
                    hasPageNumber = true;
                }
            }
            
            // 检查段落中的运行
            if (!hasPageNumber) {
                for (XWPFRun run : p.getRuns()) {
                    if (checkRunForPageNumber(run)) {
                        hasPageNumber = true;
                        break;
                    }
                }
            }
            
            if (hasPageNumber) {
                log.info("段落包含页码，处理其中的运行...");
                // 精确处理段落中的运行
                processRunsInPageNumberParagraph(p);
            } else {
                log.info("段落不包含页码，清空内容");
                // 清空不包含页码的段落
                for (int i = p.getRuns().size() - 1; i >= 0; i--) {
                    p.removeRun(i);
                }
            }
        } catch (Exception e) {
            log.error("处理页脚段落时出错: {}", e.getMessage());
        }
    }
    
    /**
     * 检查运行是否包含页码
     */
    private boolean checkRunForPageNumber(XWPFRun run) {
        try {
            // 检查运行文本
            String runText = run.getText(0);
            if (runText != null && containsPageNumber(runText)) {
                return true;
            }
            
            // 检查运行XML内容
            if (run.getCTR() != null) {
                String runXml = run.getCTR().xmlText();
                if (runXml.contains("w:fldChar") || 
                    runXml.contains("PAGE") || 
                    runXml.contains("w:instrText")) {
                    return true;
                }
                
                // 检查字段字符
                CTFldChar[] fldChars = run.getCTR().getFldCharArray();
                if (fldChars != null && fldChars.length > 0) {
                    return true;
                }
                
                // 检查指令文本
                CTText[] instrTexts = run.getCTR().getInstrTextArray();
                if (instrTexts != null && instrTexts.length > 0) {
                    for (CTText instr : instrTexts) {
                        if (instr.getStringValue() != null && 
                            (instr.getStringValue().contains("PAGE") || 
                             instr.getStringValue().contains("页码"))) {
                            return true;
                        }
                    }
                }
            }
            
            return false;
        } catch (Exception e) {
            log.debug("检查运行时出错: {}", e.getMessage());
            return false;
        }
    }
    
    /**
     * 处理包含页码的段落中的运行
     */
    private void processRunsInPageNumberParagraph(XWPFParagraph p) {
        try {
            // 标记包含页码的运行
            List<Integer> pageNumberRunIndexes = new ArrayList<>();
            
            // 标记所有字段运行 - 需要保留完整的PAGE字段
            List<Integer> fieldRunIndexes = new ArrayList<>();
            List<Integer> beginFieldIndexes = new ArrayList<>();
            List<Integer> separateFieldIndexes = new ArrayList<>();
            List<Integer> endFieldIndexes = new ArrayList<>();
            
            // 首先检测所有字段开始和结束标记
            for (int i = 0; i < p.getRuns().size(); i++) {
                XWPFRun run = p.getRuns().get(i);
                if (run.getCTR() != null) {
                    // 检查是否包含字段字符
                    for (CTFldChar fldChar : run.getCTR().getFldCharArray()) {
                        if (fldChar.getFldCharType() != null) {
                            String type = fldChar.getFldCharType().toString();
                            if ("BEGIN".equals(type)) {
                                beginFieldIndexes.add(i);
                            } else if ("SEPARATE".equals(type)) {
                                separateFieldIndexes.add(i);
                            } else if ("END".equals(type)) {
                                endFieldIndexes.add(i);
                            }
                        }
                    }
                    
                    // 检查是否包含页码相关指令
                    for (CTText instrText : run.getCTR().getInstrTextArray()) {
                        if (instrText.getStringValue() != null && 
                            (instrText.getStringValue().contains("PAGE") || 
                             instrText.getStringValue().contains("页码"))) {
                            fieldRunIndexes.add(i);
                        }
                    }
                    
                    // 检查运行是否包含页码
                    if (checkRunForPageNumber(run)) {
                        pageNumberRunIndexes.add(i);
                    }
                }
            }
            
            // 标记完整的字段范围
            List<Integer> completeFieldRuns = new ArrayList<>();
            for (int beginIndex : beginFieldIndexes) {
                for (int endIndex : endFieldIndexes) {
                    if (endIndex > beginIndex) {
                        // 添加从开始到结束的所有运行
                        for (int i = beginIndex; i <= endIndex; i++) {
                            completeFieldRuns.add(i);
                        }
                        break;
                    }
                }
            }
            
            // 合并所有需要保留的运行索引
            pageNumberRunIndexes.addAll(fieldRunIndexes);
            pageNumberRunIndexes.addAll(completeFieldRuns);
            
            // 删除重复索引并排序
            List<Integer> allRunsToKeep = new ArrayList<>(new java.util.HashSet<>(pageNumberRunIndexes));
            java.util.Collections.sort(allRunsToKeep);
            
            // 如果找到了需要保留的运行
            if (!allRunsToKeep.isEmpty()) {
                // 从后向前删除不需要保留的运行
                for (int i = p.getRuns().size() - 1; i >= 0; i--) {
                    if (!allRunsToKeep.contains(i)) {
                        log.debug("移除不包含页码的运行 [{}]", i);
                        p.removeRun(i);
                    }
                }
                log.info("保留了页码，移除了其他内容");
            } else {
                // 如果没有找到任何需要保留的运行，但段落被标记为包含页码
                // 保守处理，保留第一个运行
                log.info("未找到具体的页码运行，保守处理");
                for (int i = p.getRuns().size() - 1; i > 0; i--) {
                    p.removeRun(i);
                }
            }
        } catch (Exception e) {
            log.error("处理段落运行时出错: {}", e.getMessage());
        }
    }
    
    /**
     * 处理页脚表格
     */
    private void processFooterTable(XWPFFooter footer, XWPFTable table) {
        try {
            boolean tableHasPageNumber = false;
            
            // 检查表格中的所有单元格是否包含页码
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph p : cell.getParagraphs()) {
                        // 检查段落文本
                        if (p.getText() != null && containsPageNumber(p.getText())) {
                            tableHasPageNumber = true;
                            log.info("表格中检测到页码，保留此表格");
                            break;
                        }
                        
                        // 检查段落中的运行
                        for (XWPFRun run : p.getRuns()) {
                            if (checkRunForPageNumber(run)) {
                                tableHasPageNumber = true;
                                break;
                            }
                        }
                        
                        if (tableHasPageNumber) break;
                    }
                    if (tableHasPageNumber) break;
                }
                if (tableHasPageNumber) break;
            }
            
            // 如果表格包含页码，处理表格中的内容
            if (tableHasPageNumber) {
                for (XWPFTableRow row : table.getRows()) {
                    for (XWPFTableCell cell : row.getTableCells()) {
                        for (XWPFParagraph p : cell.getParagraphs()) {
                            processFooterParagraph(p);
                        }
                    }
                }
            } else {
                // 如果表格不包含页码，移除它
                footer.removeTable(table);
            }
        } catch (Exception e) {
            log.error("处理页脚表格时出错: {}", e.getMessage());
        }
    }
    
    /**
     * 清理页脚中其他元素
     */
    private void cleanUpFooterElements(XWPFFooter footer) {
        // 可以添加其他清理逻辑，如移除图片、形状等
    }
    
    /**
     * 清理文档中的页脚设置但保留页码相关设置
     */
    private void cleanupDocumentFooterSettings(XWPFDocument document) {
        // 保留页码相关设置，清理其他页脚设置
    }
    
    /**
     * 检查文本是否包含页码相关的字段代码或文本
     * @param text 要检查的文本
     * @return 是否包含页码
     */
    private boolean containsPageNumber(String text) {
        if (text == null) return false;
        
        // 检查常见的页码字段代码和文本
        return text.contains("PAGE") || 
               text.contains("Page") || 
               text.contains("page") || 
               text.contains("页码") ||
               text.contains("页次") ||
               text.contains("页号") ||
               text.contains("第") && text.contains("页") || // 常见格式"第X页"
               text.matches(".*\\d+.*(/|\\\\|的|共|/|\\s).*\\d+.*") || // 匹配类似 "1/5" 或 "第1页共5页" 格式
               text.matches(".*[Pp]age.*\\d+.*of.*\\d+.*"); // 匹配 "Page X of Y" 格式
    }
    
    /**
     * 获取处理后的Word文件
     * @param filename 文件名
     * @return 文件对象
     */
    public File getWordFile(String filename) {
        return new File(uploadDirFile, filename);
    }
    
    /**
     * 删除Word文件
     * @param filename 文件名
     */
    public void deleteWordFile(String filename) {
        try {
            File fileToDelete = new File(uploadDirFile, filename);
            if (fileToDelete.exists()) {
                fileToDelete.delete();
            }
        } catch (Exception e) {
            log.error("删除文件失败: {}", filename, e);
        }
    }
} 